// -*- swift -*-
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test

import StdlibUnittest
import StdlibCollectionUnittest

var CollectionTests = TestSuite("Collection")

%{
variations = [('', 'Sequence'), ('', 'Collection'), ('Bidirectional', 'Collection'), ('RandomAccess', 'Collection')]
}%

// Test collections using value types as elements.
% for (traversal, kind) in variations:
CollectionTests.add${traversal}${kind}Tests(
  make${kind}: { (elements: [OpaqueValue<Int>]) -> LazyMap${traversal}${kind}<Minimal${traversal}${kind}<OpaqueValue<Int>>, OpaqueValue<Int>> in
    Minimal${traversal}${kind}(elements: elements).lazy.map(identity)
  },
  wrapValue: identity,
  extractValue: identity,
  make${kind}OfEquatable: { (elements: [MinimalEquatableValue]) -> LazyMap${traversal}${kind}<Minimal${traversal}${kind}<MinimalEquatableValue>, MinimalEquatableValue> in
    Minimal${traversal}${kind}(elements: elements).lazy.map(identityEq)
  },
  wrapValueIntoEquatable: identityEq,
  extractValueFromEquatable: identityEq
)
% end

// Test collections using reference types as elements.
% for (traversal, kind) in variations:
CollectionTests.add${traversal}${kind}Tests(
  make${kind}: { (elements: [LifetimeTracked]) -> LazyMap${traversal}${kind}<Minimal${traversal}${kind}<LifetimeTracked>, LifetimeTracked> in
    Minimal${traversal}${kind}(elements: elements).lazy.map { $0 }
  },
  wrapValue: { (element: OpaqueValue<Int>) in
    LifetimeTracked(element.value, identity: element.identity)
  },
  extractValue: { (element: LifetimeTracked) in
    OpaqueValue(element.value, identity: element.identity)
  },
  make${kind}OfEquatable: { (elements: [LifetimeTracked]) -> LazyMap${traversal}${kind}<Minimal${traversal}${kind}<LifetimeTracked>, LifetimeTracked> in
    Minimal${traversal}${kind}(elements: elements).lazy.map { $0 }
  },
  wrapValueIntoEquatable: { (element: MinimalEquatableValue) in
    LifetimeTracked(element.value, identity: element.identity)
  },
  extractValueFromEquatable: { (element: LifetimeTracked) in
    MinimalEquatableValue(element.value, identity: element.identity)
  }
)
% end

// Test sequence instances and iterators.
% for (traversal, kind) in variations:
CollectionTests.test("LazyMapCollection instances (${traversal}${kind})") {
  do {
    let expected = ["convent", "conform", "constrict", "condone"]
    let base = ["vent", "form", "strict", "done"]
% if kind == 'Sequence':
    checkSequence(
      expected,
      MinimalSequence(elements: base).lazy.map { "con" + $0 })
% elif traversal == '' and kind == 'Collection':
    checkForwardCollection(expected,
      MinimalCollection(elements: base).lazy.map { "con" + $0 },
      sameValue: { $0 == $1 })
% else:
    check${traversal}${kind}(expected,
      Minimal${traversal}${kind}(elements: base).lazy.map { "con" + $0 },
      sameValue: { $0 == $1 })
% end
  }
  do {
    let expected = [1, 4, 9, 16, 25, 36, 49, 64]
    let base = [1, 2, 3, 4, 5, 6, 7, 8]
% if kind == 'Sequence':
    checkSequence(
      expected,
      MinimalSequence(elements: base).lazy.map { $0 * $0 })
% elif traversal == '' and kind == 'Collection':
    checkForwardCollection(expected,
      MinimalCollection(elements: base).lazy.map { $0 * $0 },
      sameValue: { $0 == $1 })
% else:
    check${traversal}${kind}(
      expected,
      Minimal${traversal}${kind}(elements: base).lazy.map { $0 * $0 },
      sameValue: { $0 == $1 })
% end
  }
}
% end

runAllTests()
